﻿using UnityEngine;
using UniRx;
using Cysharp.Threading.Tasks;

public class MonsterSpawner : USaBehaviour
{
    [SerializeField, Tooltip("当前刷新点所刷新的怪物ID")]
    private int m_MonsterID;

    [SerializeField, Tooltip("当前点允许刷新的最大怪物数量")]
    private int m_MaxMonsterCount;

    [SerializeField, Tooltip("当前点怪物数量未达上限时，刷新所需的间隔时间（单位秒）")]
    private float m_SpawnInterval;

    [SerializeField, Tooltip("完成加载时是否立刻生成第一个")]
    private bool m_SpawnFirstImmediately;

    /// <summary>
    /// 该生成点的怪物配置
    /// </summary>
    public MonsterConfig monsterConfig { get; private set; }

    /// <summary>
    /// 怪物属性
    /// </summary>
    public MonsterAttributeConfig monsterAttributeConfig { get; private set; }

    /// <summary>
    /// 实例存放路径
    /// </summary>
    public Transform spawnRoot => m_SpawnRoot ??= (GameObject.Find(MONSTER_OBJECT_ROOT_PATH) ?? Tools.CreateGameObjectByPath(MONSTER_OBJECT_ROOT_PATH)).transform;
    private Transform m_SpawnRoot;


    private const string MONSTER_OBJECT_ROOT_PATH = "Units/Monsters";
    private const string PREFAB_ROOT_PATH = "MonsterPrefabs/{0}.prefab";
    private static AssetCache<string, GameObject> s_MonsterPrefabCaches = new AssetCache<string, GameObject>(PREFAB_ROOT_PATH);


    private ReactiveCollection<MonsterEntity> m_Monsters = new ReactiveCollection<MonsterEntity>();
    private ObjectPool<MonsterEntity> m_Pool;
    private Timer.Simple m_SpawnTimer = new Timer.Simple();


    private async void Awake()
    {
        await GameConstructor.WaitForReady();
        monsterConfig = ConfigLoader.GetConfig<MonsterConfig>().Find(c => c.id == m_MonsterID);
        monsterAttributeConfig = ConfigLoader.GetConfig<MonsterAttributeConfig>().Find(c => c.id == m_MonsterID);
        var prefab = await s_MonsterPrefabCaches.LoadAsync(monsterConfig.assetName);
        m_Pool = new ObjectPool<MonsterEntity>(prefab, mon =>
        {
            mon.SignSpawner(this);
            mon.Init();
        });
        m_SpawnTimer.onFinish.Subscribe(_ => Spawn()).AddTo(this);
        m_Monsters.ObserveCountChanged().Where(count => count < m_MaxMonsterCount).Subscribe(_ => StartSpawnTimer()).AddTo(this);

        ActiveSpawner();
    }

    private void OnDestroy()
    {
        while (m_Monsters.Count > 0)
        {
            var mon = m_Monsters[0];
            if (mon == null)
                m_Monsters.RemoveAt(0);
            else
                Despawn(m_Monsters[0]);
        }
    }

    public void ActiveSpawner()
    {
        if (m_SpawnFirstImmediately)
        {
            Spawn();
        }
        StartSpawnTimer();
    }

    private void StartSpawnTimer()
    {
        m_SpawnTimer.Start(m_SpawnInterval);
    }

    private void Spawn()
    {
        if (m_Monsters.Count >= m_MaxMonsterCount) return;
        var monster = m_Pool.Rent();
        m_Monsters.Add(monster);
        monster.transform.parent = spawnRoot.transform;
        monster.transform.position = transform.position;
        monster.Spawn();
    }

    public void Despawn(MonsterEntity monster)
    {
        m_Monsters.Remove(monster);
        m_Pool.Return(monster);
    }
}